package main

import (
	"encoding/json"
	"fmt"
	r "math/rand"
	"strconv"
	"time"

	"github.com/hyperledger/fabric/core/chaincode/shim"
	"github.com/hyperledger/fabric/protos/peer"
)

type DepartmentGo struct{}

type Department struct {
	Table          string `json:"Table,omitempty"`
	Key            string `json:"key,omitempty"`
	DepartmentName string `json:"DepartmentName,omitempty"`
	CreateTime     string `json:"CreateTime,omitempty"`
	UpdateTime     string `json:"UpdateTime,omitempty"`
	CompanyKey     string `json:"CompanyKey,omitempty"`
	DepartmentType string `json:"DepartmentType,omitempty"` // 用于标识处于哪个环节：贴标签、生产、运输
	PageNo         uint64 `json:"PageNo,omitempty"`
	PageSize       uint   `json:"PageSize,omitempty"`
}

type DE struct {
	Table      string `json:"Table,omitempty"`
	Key        string `json:"key,omitempty"`
	DEDKey     string `json:"DEDKey,omitempty"`
	DEEKey     string `json:"DEEKey,omitempty"`
	CreateTime string `json:"CreateTime,omitempty"`
	Desc       string `json:"Desc,omitempty"`
	PageNo     uint64 `json:"PageNo,omitempty"`
}

// 2018-08-08  added by lionel
type Company struct {
	Table       string `json:"Table,omitempty"`
	Key         string `json:"key,omitempty"`
	CompanyName string `json:"CompanyName,omitempty"`
	CreateTime  string `json:"CreateTime,omitempty"`
	UpdateTime  string `json:"UpdateTime,omitempty"`
}

type MangoCompany struct {
	SelectorCompany Company `json:"selector"`
}

//end

type Mango struct {
	Selector Department `json:"selector"`
}

//type MangoCount struct {
//	SelectorCount Count `json:"selector"`
//}
type MangoDE struct {
	SelectorDE DE `json:"selector"`
}

func (s *DepartmentGo) Init(stub shim.ChaincodeStubInterface) peer.Response {
	fmt.Println(time.Now().Format("2006-01-02 15:04:05"), "   init chaincode ,chaincode name : department ,version :1.0")
	return shim.Success(nil)
}
func (s *DepartmentGo) Invoke(stub shim.ChaincodeStubInterface) peer.Response {

	function, args := stub.GetFunctionAndParameters()

	if function == "DepartmentAdd" {
		return s.DepartmentAdd(stub, args)
	} else if function == "DepartmentUpdate" {
		return s.DepartmentUpdate(stub, args)
	} else if function == "DepartmentDel" {
		return s.DepartmentDel(stub, args)
	} else if function == "DepartmentSelect" {
		return s.DepartmentSelect(stub, args)
	} else if function == "DEAdd" {
		return s.DEAdd(stub, args)
	} else if function == "DESelect" {
		return s.DESelect(stub, args)
	} else if function == "CompanyAdd" {
		return s.CompanyAdd(stub, args)
	} else if function == "CompanyUpdate" {
		return s.CompanyUpdate(stub, args)
	} else if function == "CompanyQuery" {
		return s.CompanyQuery(stub, args)
	}
	return shim.Error("Invalid Smart Contract function name.")
}

func main() {
	err := shim.Start(new(DepartmentGo))
	if err != nil {
		fmt.Printf("Error creating new  Contract: %s", err)
	}
}

//----------------------------------------------------公司 部分-------------------------------------------------------//
// 2018-08-08 added by lionel
/*
 * 公司名称添加
 */
func (s *DepartmentGo) CompanyAdd(stub shim.ChaincodeStubInterface, args []string) peer.Response {
	fmt.Println(time.Now().Format("2006-01-02 15:04:05"), "   function is : CompanyAdd", args)
	var o Company

	err := json.Unmarshal([]byte(args[0]), &o)
	if err != nil {
		return shim.Error("Incorrect parameters,please check your parameters")
	}
	if o.CompanyName == "" {
		return shim.Error("parameters have null string,please check your parameters")
	}

	o.CreateTime = time.Now().Format("2006-01-02 15:04:05")
	o.UpdateTime = time.Now().Format("2006-01-02 15:04:05")
	dbData, _ := json.Marshal(o)
	r.Seed(time.Now().UnixNano())
	randNum := r.Int63n(100000000)
	key := strconv.FormatInt(time.Now().Unix()+randNum, 10)

	stub.PutState(key, dbData)
	fmt.Println(time.Now().Format("2006-01-02 15:04:05"), "   CompanyAdd exec success")
	return shim.Success(nil)
}

/*
 * 公司信息更新
 */
func (s *DepartmentGo) CompanyDetail(stub shim.ChaincodeStubInterface, key string) (Company, error) {
	var company Company
	companyBytes, err := stub.GetState(key)
	if err != nil {
		return company, err
	}
	err = json.Unmarshal(companyBytes, &company) //反序列化
	if err != nil {
		return company, err
	}
	return company, nil
}

func (s *DepartmentGo) CompanyUpdate(stub shim.ChaincodeStubInterface, args []string) peer.Response {
	fmt.Println(time.Now().Format("2006-01-02 15:04:05"), "   function is : CompanyUpdate", args)
	//获取详情
	key := args[0]
	company, err := s.CompanyDetail(stub, key)
	if err != nil {
		return shim.Error("Detail func error")
	}
	//根据条件替换详情
	var o Company
	err = json.Unmarshal([]byte(args[1]), &o)
	if err != nil {
		return shim.Error("Incorrect parameters,please check your parameters")
	}
	if o.CompanyName != "" {
		company.CompanyName = o.CompanyName
	}
	company.UpdateTime = time.Now().Format("2006-01-02 15:04:05")
	company.Key = ""
	dbData, _ := json.Marshal(company)
	stub.PutState(key, dbData)
	fmt.Println(time.Now().Format("2006-01-02 15:04:05"), "   DepartmentUpdate exec success")
	return shim.Success(nil)
}

/*
 * 公司信息查询
 */
func (s *DepartmentGo) CompanyQuery(stub shim.ChaincodeStubInterface, args []string) peer.Response {
	fmt.Println(time.Now().Format("2006-01-02 15:04:05"), "   function is : CompanyQuery", args)
	var o Company
	err := json.Unmarshal([]byte(args[0]), &o)
	if err != nil {
		return shim.Error(err.Error())
	}

	queryObject := MangoCompany{
		SelectorCompany: o,
	}

	queryString, err := json.Marshal(queryObject)
	if err != nil {
		return shim.Error(err.Error())
	}
	fmt.Println(time.Now().Format("2006-01-02 15:04:05"), "   query string is : ", string(queryString))
	resultsIterator, err := stub.GetQueryResult(string(queryString))

	defer resultsIterator.Close()
	var results []Company
	for resultsIterator.HasNext() {
		var result Company
		queryResponse, err := resultsIterator.Next()
		if err != nil {
			return shim.Error(err.Error())
		}
		err = json.Unmarshal(queryResponse.GetValue(), &result)
		if err != nil {
			return shim.Error(err.Error())
		}
		result.Key = queryResponse.GetKey()
		results = append(results, result)
	}

	resp, _ := json.Marshal(results)
	fmt.Println(time.Now().Format("2006-01-02 15:04:05"), "   CompanyQuery exec success")
	return shim.Success(resp)
}

// end

//----------------------------------------------------部门 部分-------------------------------------------------------//

/*
 * 部门添加
 */
func (s *DepartmentGo) DepartmentAdd(stub shim.ChaincodeStubInterface, args []string) peer.Response {
	fmt.Println(time.Now().Format("2006-01-02 15:04:05"), "   function is : DepartmentAdd", args)
	var o Department

	err := json.Unmarshal([]byte(args[0]), &o)
	if err != nil {
		return shim.Error("Incorrect parameters,please check your parameters")
	}
	if o.DepartmentName == "" {
		return shim.Error("parameters have null string,please check your parameters")
	}
	// 2018-08-08 added by lionel
	if o.CompanyKey == "" {
		return shim.Error("parameters have null string,please check your parameters")
	}
	if o.DepartmentType == "" {
		return shim.Error("parameters have null string,please check your parameters")
	}
	// end

	o.CreateTime = time.Now().Format("2006-01-02 15:04:05")
	o.UpdateTime = time.Now().Format("2006-01-02 15:04:05")
	o.PageNo = 1
	o.PageSize = 1
	dbData, _ := json.Marshal(o)
	r.Seed(time.Now().UnixNano())
	randNum := r.Int63n(100000000)
	key := strconv.FormatInt(time.Now().Unix()+randNum, 10)

	stub.PutState(key, dbData)
	fmt.Println(time.Now().Format("2006-01-02 15:04:05"), "   DepartmentAdd exec success")
	return shim.Success(nil)
}

/*
 * 部门更新
 */
func (s *DepartmentGo) DepartmentUpdate(stub shim.ChaincodeStubInterface, args []string) peer.Response {
	fmt.Println(time.Now().Format("2006-01-02 15:04:05"), "   function is : DepartmentUpdate", args)
	//获取详情
	key := args[0]
	department, err := s.DepartmentDetail(stub, key)
	if err != nil {
		return shim.Error("Detail func error")
	}
	//根据条件替换详情
	var o Department
	err = json.Unmarshal([]byte(args[1]), &o)
	if err != nil {
		return shim.Error("Incorrect parameters,please check your parameters")
	}
	if o.DepartmentName != "" {
		department.DepartmentName = o.DepartmentName
	}
	// 2018-08-08 added by lionel
	if o.CompanyKey != "" {
		department.CompanyKey = o.CompanyKey
	}
	if o.DepartmentType != "" {
		department.DepartmentType = o.DepartmentType
	}
	// end

	department.UpdateTime = time.Now().Format("2006-01-02 15:04:05")
	department.Key = ""
	dbData, _ := json.Marshal(department)
	stub.PutState(key, dbData)
	fmt.Println(time.Now().Format("2006-01-02 15:04:05"), "   DepartmentUpdate exec success")
	return shim.Success(nil)
}

/*
 * 部门删除
 */
func (s *DepartmentGo) DepartmentDel(stub shim.ChaincodeStubInterface, args []string) peer.Response {
	fmt.Println(time.Now().Format("2006-01-02 15:04:05"), "   function is : DepartmentDel", args)

	key := args[0]
	if key == "" {
		return shim.Error("Failed to delete Student from DB, key is: " + key)
	}

	err := stub.DelState(key)
	if err != nil {
		return shim.Error("Failed to delete Student from DB, key is: " + key)
	}
	fmt.Println(time.Now().Format("2006-01-02 15:04:05"), "   afc_data_delete exec success")
	return shim.Success(nil)
}

/*
 * 部门查询
 */
func (s *DepartmentGo) DepartmentSelect(stub shim.ChaincodeStubInterface, args []string) peer.Response {
	fmt.Println(time.Now().Format("2006-01-02 15:04:05"), "   function is : DepartmentSelect", args)
	var o Department
	err := json.Unmarshal([]byte(args[0]), &o)
	if err != nil {
		return shim.Error(err.Error())
	}

	queryObject := Mango{
		Selector: o,
	}
	queryString, err := json.Marshal(queryObject)
	if err != nil {
		return shim.Error(err.Error())
	}
	fmt.Println(time.Now().Format("2006-01-02 15:04:05"), "   query string is : ", string(queryString))
	resultsIterator, err := stub.GetQueryResult(string(queryString))

	defer resultsIterator.Close()
	var results []Department
	for resultsIterator.HasNext() {
		var result Department
		queryResponse, err := resultsIterator.Next()
		if err != nil {
			return shim.Error(err.Error())
		}
		err = json.Unmarshal(queryResponse.GetValue(), &result)
		if err != nil {
			return shim.Error(err.Error())
		}
		result.Key = queryResponse.GetKey()
		results = append(results, result)
	}

	resp, _ := json.Marshal(results)
	fmt.Println(time.Now().Format("2006-01-02 15:04:05"), "   DepartmentSelect exec success")
	return shim.Success(resp)
}

func (s *DepartmentGo) DepartmentDetail(stub shim.ChaincodeStubInterface, key string) (Department, error) {
	var department Department
	departmentBytes, err := stub.GetState(key)
	if err != nil {
		return department, err
	}
	err = json.Unmarshal(departmentBytes, &department) //反序列化
	if err != nil {
		return department, err
	}
	return department, nil
}

//----------------------------------------------------DE 部分--------------------------------------------------------------//
/*
 * DE 添加
 */
func (s *DepartmentGo) DEAdd(stub shim.ChaincodeStubInterface, args []string) peer.Response {
	fmt.Println(time.Now().Format("2006-01-02 15:04:05"), "   function is : DEAdd", args)
	//一、数据转换和验证处理
	var o DE
	err := json.Unmarshal([]byte(args[0]), &o)
	if err != nil {
		return shim.Error("Incorrect parameters,please check your parameters")
	}
	if o.DEDKey == "" || o.DEEKey == "" {
		return shim.Error("parameters have null string,please check your parameters")
	}

	//二、更新depart表
	departmentBytes, err := stub.GetState(o.DEDKey)
	var department Department
	err = json.Unmarshal(departmentBytes, &department)
	if err != nil {
		return shim.Error("{\"Error\":\"Failed to decode JSON of: " + string(departmentBytes) + "\"}")
	}
	if department.PageSize == 21 {
		department.PageNo++
		department.PageSize = 2
	} else {
		department.PageSize++
	}
	departmentBytes, _ = json.Marshal(department)
	stub.PutState(o.DEDKey, departmentBytes)

	//三、插入DE
	o.PageNo = department.PageNo
	o.CreateTime = time.Now().Format("2006-01-02-15:04:05")
	dbData, _ := json.Marshal(o)

	s.PutState(stub, dbData)

	fmt.Println(time.Now().Format("2006-01-02 15:04:05"), "   afc_data_add exec success")
	return shim.Success(nil)
}

/*
 * DE 查询
 */
func (s *DepartmentGo) DESelect(stub shim.ChaincodeStubInterface, args []string) peer.Response {
	fmt.Println(time.Now().Format("2006-01-02 15:04:05"), "   function is : DESelect", args)
	var o DE
	err := json.Unmarshal([]byte(args[0]), &o)
	if err != nil {
		return shim.Error(err.Error())
	}
	if o.DEDKey == "" && o.DEEKey == "" {
		return shim.Error("parameters have null string,please check your parameters")
	}
	if o.PageNo == 0 {
		return shim.Error("parameters have null string,please check your parameters")
	}
	queryObject := MangoDE{
		SelectorDE: o,
	}
	queryString, err := json.Marshal(queryObject)
	if err != nil {
		return shim.Error(err.Error())
	}
	fmt.Println(time.Now().Format("2006-01-02 15:04:05"), "   query string is : ", string(queryString))
	resultsIterator, err := stub.GetQueryResult(string(queryString))

	defer resultsIterator.Close()
	var results []DE
	for resultsIterator.HasNext() {
		var result DE
		queryResponse, err := resultsIterator.Next()
		if err != nil {
			return shim.Error(err.Error())
		}
		err = json.Unmarshal(queryResponse.GetValue(), &result)
		if err != nil {
			return shim.Error(err.Error())
		}

		result.Key = queryResponse.GetKey()
		results = append(results, result)
	}

	resp, _ := json.Marshal(results)
	fmt.Println(time.Now().Format("2006-01-02 15:04:05"), "   CountSelect exec success")
	return shim.Success(resp)
}

//----------------------------------------------------功能 方法--------------------------------------------------------------//
func (s *DepartmentGo) PutState(stub shim.ChaincodeStubInterface, bytes []byte) {
	r.Seed(time.Now().UnixNano())
	randNum := r.Int63n(100000000)
	key := strconv.FormatInt(time.Now().Unix()+randNum, 10)
	stub.PutState(key, bytes)
}
